/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.hd4ic.algorithm.realizations;

import edu.hd4ic.algorithm.base.AbstractHDBasedAlgorithm;

/**
 * @author morfant
 */
public class HausdorffDistance extends AbstractHDBasedAlgorithm {

    protected double calculateDirectDistance(int[] firstImageDataBlock, int[] secondImageDataBlock, int width, int height) {
        double maxDistance = 0.0;
        double distanceFromPixelToSet;
        int pixelValue;
        int i, j;

        for (i = 0; i < height; i++) {
            for (j = 0; j < width; j++) {
                pixelValue = firstImageDataBlock[i * width + j];
                if (pixelValue > 0) {
                    distanceFromPixelToSet = calculateDistanceFromPixelToSet(i, j, secondImageDataBlock, width, height);
                    if (distanceFromPixelToSet > maxDistance) {
                        maxDistance = distanceFromPixelToSet;
                    }
                }
            }
        }

        return maxDistance;
    }

    private double calculateDistanceFromPixelToSet(int x, int y, int[] secondImageDataBlock, int width, int height) {
        double distance = 0.0;
        double minDistance = Double.MAX_VALUE;

        int searchIndent = 0;
        int cochleaLenght;
        int pixelValue;

        int i, j, destinationX, destinationY;

        boolean isFound = false;

        while (!isFound) {
            cochleaLenght = 2 * searchIndent + 1;
            for (i = 0; i < cochleaLenght; i++) {

                if ((i == 0) || (i == cochleaLenght - 1)) {//Первая и последняя строки. Интересуют все элементы строки.

                    for (j = 0; j < cochleaLenght; j++) {

                        destinationX = x - searchIndent + i;
                        destinationY = y - searchIndent + j;

                        if (checkThatPositionIsWithinImage(destinationX, destinationY, width, height)) {

                            pixelValue = secondImageDataBlock[destinationX * width + destinationY];

                            if (pixelValue > 0) {

                                isFound = true;
                                distance = calculateEuclideanSpace(x, y, destinationX, destinationY);
                                if (distance < minDistance) {
                                    minDistance = distance;
                                }

                            }
                        }

                    }
                } else {//Промежуточные строки - когда нас интересуют только первый и последний элемент строки.
                    destinationX = x - searchIndent + i;
                    destinationY = y - searchIndent;

                    if (checkThatPositionIsWithinImage(destinationX, destinationY, width, height)) {

                        pixelValue = secondImageDataBlock[destinationX * width + destinationY];

                        if (pixelValue > 0) {

                            isFound = true;
                            distance = calculateEuclideanSpace(x, y, destinationX, destinationY);
                            if (distance < minDistance) {
                                minDistance = distance;
                            }

                        }
                    }


                    destinationX = x - searchIndent + i;
                    destinationY = y + searchIndent;

                    if (checkThatPositionIsWithinImage(destinationX, destinationY, width, height)) {

                        pixelValue = secondImageDataBlock[destinationX * width + destinationY];

                        if (pixelValue > 0) {

                            isFound = true;
                            distance = calculateEuclideanSpace(x, y, destinationX, destinationY);
                            if (distance < minDistance) {
                                minDistance = distance;
                            }

                        }
                    }
                }
            }
            if (!isFound) {
                searchIndent++;
                if (!checkThatWorkIsDoingWithinImage(x, y, searchIndent, width, height)) {
//                    throw new RuntimeException("Полный выход за пределы изображения - одно из изображений пусто.");
                    return Double.MAX_VALUE;
                }
            }
        }

        return minDistance;
    }

    private boolean checkThatWorkIsDoingWithinImage(int x, int y, int indent, int widht, int height) {
        return (x - indent >= 0)//Вверх изображения
                || (y - indent >= 0)//Левая часть изображения
                || (x + indent < widht)//Низ изображения
                || (y + indent < height);//Правая часть изображения
    }

    private boolean checkThatPositionIsWithinImage(int x, int y, int widht, int height) {
        return (x >= 0)
                && (y >= 0)
                && (x < widht)
                && (y < height);
    }

    private double calculateEuclideanSpace(int beginX, int beginY, int endX, int endY) {
        return Math.sqrt(Math.pow(beginX - endX, 2) + Math.pow(beginY - endY, 2));
    }
}
